//
//  ZCharsetPrivate.h
//  Part of Z-Way.C library
//
//  Created by Pavel Kulaha.
//
//  Copyright (c) 2021 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zcharset_private_h
#define zcharset_private_h

#include "ZPlatform.h"
#include "ZLogPrivate.h"

typedef size_t (*_zcharset_encode_t)(ZWDWORD unicode, ZWSTR const output);

typedef size_t (*_zcharset_decode_t)(const ZWBYTE *const data, const size_t input_length, ZWDWORD *const output);

ZWEXPORT_PRIVATE size_t _zcharset_encode_utf16be(ZWDWORD unicode, ZWSTR const output);
ZWEXPORT_PRIVATE size_t _zcharset_encode_utf8(ZWDWORD unicode, ZWSTR const output);
ZWEXPORT_PRIVATE size_t _zcharset_encode_ansii(ZWDWORD unicode, ZWSTR const output);
ZWEXPORT_PRIVATE size_t _zcharset_encode_cp437(ZWDWORD unicode, ZWSTR const output);

ZWEXPORT_PRIVATE size_t _zcharset_decode_utf16be(const ZWBYTE *const data, const size_t input_length, ZWDWORD *const output);
ZWEXPORT_PRIVATE size_t _zcharset_decode_cp437(const ZWBYTE *const data, const size_t input_length, ZWDWORD *const output);
ZWEXPORT_PRIVATE size_t _zcharset_decode_ansii(const ZWBYTE *const data, const size_t input_length, ZWDWORD *const output);
ZWEXPORT_PRIVATE size_t _zcharset_decode_utf8(const ZWBYTE *const data, const size_t input_length, ZWDWORD *const output);

typedef struct _ZCharsetOption_s
{
    _zcharset_decode_t decoder;
    ZWCSTR decoder_name;
    _zcharset_encode_t encoder;
    ZWCSTR encoder_name;
} _ZCharsetOption_t;

#define ZCHARSET_FLAGS_TRIM_NON_PRINTABLE (1 << 0)
#define ZCHARSET_FLAGS_DONT_SET_ZERO_STR (1 << 1)

#define ZCHARSET_FLAGS_PROCESS_REPLACE_INPUT (1 << 29)
#define ZCHARSET_FLAGS_PROCESS_ALLOC_IF_CHANGE (1 << 30)
#define ZCHARSET_FLAGS_PROCESS_DONT_ALLOC_IF_ZERO (1 << 31)

ZWEXPORT_PRIVATE ZWError _zcharset_decode_x_to_encode_y(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags, const _ZCharsetOption_t *const option);
ZWEXPORT_PRIVATE ZWError _zcharset_process_chars(const ZWLog log, const void *const input, const size_t input_length, void **const p_output, size_t *const p_output_length, const ZWDWORD flags, const _ZCharsetOption_t *const option);

static inline ZWError _zcharset_utf8_to_utf16be(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_utf8,
            .decoder_name = "utf8",
            .encoder = _zcharset_encode_utf16be,
            .encoder_name = "utf16be",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};
static inline ZWError _zcharset_utf16be_to_utf8(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_utf16be,
            .decoder_name = "utf16be",
            .encoder = _zcharset_encode_utf8,
            .encoder_name = "utf8",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};
static inline ZWError _zcharset_ansii_to_utf8(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_ansii,
            .decoder_name = "ansii",
            .encoder = _zcharset_encode_utf8,
            .encoder_name = "utf8",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};
static inline ZWError _zcharset_utf8_to_ansii(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_utf8,
            .decoder_name = "utf8",
            .encoder = _zcharset_encode_ansii,
            .encoder_name = "ansii",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};
static inline ZWError _zcharset_cp437_to_utf8(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_cp437,
            .decoder_name = "cp437",
            .encoder = _zcharset_encode_utf8,
            .encoder_name = "utf8",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};
static inline ZWError _zcharset_utf8_to_cp437(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
        {
            .decoder = _zcharset_decode_utf8,
            .decoder_name = "utf8",
            .encoder = _zcharset_encode_cp437,
            .encoder_name = "cp437",
        };
    return _zcharset_decode_x_to_encode_y(log, input, input_length, output, output_length, flags, &option);
};

static inline ZWError _zcharset_utf8_process(const ZWLog log, const void *const input, const size_t input_length, void **const output, size_t *const output_length, const ZWDWORD flags)
{
    static const _ZCharsetOption_t option =
    {
        .decoder = _zcharset_decode_utf8,
        .decoder_name = "utf8",
        .encoder = _zcharset_encode_utf8,
        .encoder_name = "utf8",
    };
    return _zcharset_process_chars(log, input, input_length, output, output_length, flags, &option);
};

#endif // zcharset_private_h